/**
 * Project Looking Glass
 *
 * $RCSfile: JInputDevice.java,v $
 *
 * Copyright (c) 2004-2007, Sun Microsystems, Inc., All Rights Reserved
 *
 * Redistributions in source code form must reproduce the above
 * copyright and this condition.
 *
 * The contents of this file are subject to the GNU General Public
 * License, Version 2 (the "License"); you may not use this file
 * except in compliance with the License. A copy of the License is
 * available at http://www.opensource.org/licenses/gpl-license.php.
 *
 * $Revision: 1.3 $
 * $Date: 2007/05/04 23:11:40 $
 * $State: Exp $
 */
package lionel.input;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EnumMap;
import java.util.logging.Logger;

import javax.swing.Timer;
import javax.swing.event.EventListenerList;
import net.java.games.input.Component;
import net.java.games.input.Controller;

/**
 *
 * A high level class to manage JInput devices (gamepads, joysticks etc.)
 *
 * @author Krishna Gadepalli
 */
public class JInputDevice {

    protected static final Logger logger = Logger.getLogger("lionel.input.JInputDevice");
    
    public static boolean isNavigationalDevice(Controller controller) {
	Controller.Type type = controller.getType();

	// We like GamePad and JoyStick type devices...
	if ((type == Controller.Type.GAMEPAD) ||
	    (type == Controller.Type.STICK))
	    return true;

	// We like the wiimote...
	if (controller.getName().toLowerCase().indexOf("wiimote") >= 0)
	    return true;

	else if (type == Controller.Type.MOUSE)
	    return false;

	// We like anything that has gamepad type controls
	Component[] comps = controller.getComponents();

	for (Component c: comps) {
	    if (c.getIdentifier() instanceof Component.Identifier.Axis)
		return true;
	}
	return false;
    }

    // The JInput controller
    private Controller controller;

    private JInputComponent[] components;
    private int numComponents;

    private EnumMap<JInputComponent.ID, JInputComponent> componentMap;
    
    private Timer pollTimer = null;

    /** Creates a new instance of JInputDevice */
    public JInputDevice(Controller controller) {
        this.controller = controller;

	// Get the current state of the device...
	controller.poll();

	Component[] comps = controller.getComponents();

	numComponents = (comps == null) ? 0 : comps.length;
	components    = new JInputComponent[numComponents];

	componentMap = new EnumMap<JInputComponent.ID, JInputComponent>(JInputComponent.ID.class);

	for (int i = 0; i < numComponents; i++) {
	    components[i] = JInputComponent.createComponent(this, comps[i]);
	    componentMap.put(components[i].getID(), components[i]);
	}
    }

    public String getName() {
	return controller.getName();
    }

    public Controller.Type getType() {
	return controller.getType();
    }

    public int getNumControllers() {
	return controller.getControllers().length;
    }

    public int getNumComponents() {
	return controller.getComponents().length;
    }

    public int getNumRumblers() {
	return controller.getRumblers().length;
    }

    public JInputComponent getComponent(JInputComponent.ID id) {
	return componentMap.get(id);
    }

    public float getComponentValue(JInputComponent.ID id) {
	JInputComponent c = componentMap.get(id);
	if (c != null) return c.getValue();
	return 0.0f;
    }

    /**
     * Poll the current state of the JInput device.
     * This saves the last polled state and reads in the current one.
     */
    public void poll() {
	controller.poll();

	for (JInputComponent c: components)
	    c.update();
    }

    public void sendEvents(EventListenerList listenerList) {
	for (JInputComponent c: components)
	    c.sendEvent(listenerList);
    }

    public boolean pollAndSendEvents(EventListenerList listenerList ) {
    	poll();
		if (listenerList == null)
			return false;    	
		sendEvents(listenerList);
		return true;
    }
    
    private boolean pollAndSendEvents() {
    	poll();
    	if (listenerList == null)
			return false;
		sendEvents(listenerList);
		return true;
    }
    
    public void pollDevice() {
    	if ( pollAndSendEvents(null) == false)
    		stopPolling();
    }
    
    public synchronized boolean doPolling(boolean doPolling) {
    	if (doPolling) {
    	    pollTimer = new Timer( JInput.POLL_INTERVAL,
    			    new ActionListener() {
    				public void actionPerformed(ActionEvent e) {
    					pollAndSendEvents();
    				}
    			    });
    	    startPolling();
    	} else if (pollTimer != null) {
    	    stopPolling();
    	    pollTimer = null;
    	}
        return true;
    }
    
    /**
     * Setup a timer to start polling the JInput devices at a specified time
     * interval - poll only if there are registered listeners...
     */
    private void startPolling() {
		if ((pollTimer != null) ) {
		    if (!pollTimer.isRunning())
		    	pollTimer.start();
		}
    }

    /**
     * Stop polling if there are no registered listeners...
     */
    private void stopPolling() {
		if ((pollTimer != null) && (listenerList.getListenerCount() <= 0)) {
		    if (pollTimer.isRunning())
		    	pollTimer.stop();
		}
    }    
    
    protected EventListenerList listenerList = new EventListenerList();

    public void addAxisEventListener(AxisEventListener l) {
	listenerList.add(AxisEventListener.class, l);
    }

    public void removeAxisEventListener(AxisEventListener l) {
	listenerList.remove(AxisEventListener.class, l);
    }

    public void addButtonEventListener(ButtonEventListener l) {
	listenerList.add(ButtonEventListener.class, l);
    }

    public void removeButtonEventListener(ButtonEventListener l) {
	listenerList.remove(ButtonEventListener.class, l);
    }
}
